//
//  GCDKit.swift
//  GCDKit_Test
//
//  Created by Kipp Dev on 2017/12/24.
//  Copyright © 2017年 Kipp. All rights reserved.
//

import Foundation

class GCDKit {
    static let shared = GCDKit() //单例

    typealias GCDKitClosure = () -> Void // 闭包：无参，无返回
    typealias DelayTask = (_ cancel: Bool) -> Void

    let globalQueue = DispatchQueue.global() // 异步
    let mainQueue = DispatchQueue.main //主线
    let group = DispatchGroup() // 任务组

    var closureArr = [GCDKitClosure]()

    // MARK: - 异步任务
    /// 耗时操作执行完成后回主线程调用，主线程执行闭包可以拿到异步闭包返回值；
    ///
    /// - Parameters:
    ///   - closure: 异步执行闭包
    ///   - finished: 主线程执行闭包
    func handle<T>(closure: @escaping () -> T, finished: @escaping (T) -> Void) {
        globalQueue.async {
            let data = closure()
            self.mainQueue.async {
                finished(data)
            }
        }
    }

    /// 在异步执行任务，当所有任务执行完毕后执行完成闭包，异步闭包是没有返回值的；
    ///
    /// - Parameters:
    ///   - closure: 需要异步执行的任务
    ///   - finished: 异步执行完毕后主线程需要做的
    func handle(closure: @escaping GCDKitClosure,finished: @escaping GCDKitClosure) {

        let workItem = DispatchWorkItem(block: closure)
        globalQueue.async(execute: workItem)
        workItem.wait() // 等待工作事件完成
        finished() //完成后执行完成闭包，
    }

    // MARK: - 队列
    /// 队列任务
    ///
    /// - Parameter closure: 队列需要执行的任务
    /// - Returns: GCDKit
    func wait(closure:@escaping GCDKitClosure) -> Self {
        closureArr.append(closure)
        return self
    }

    /// 队列完成
    ///
    /// - Parameter closure: 队列闭包
    func finished(closure:@escaping GCDKitClosure) {
        globalQueue.async {
            for workItem in self.closureArr {
                workItem()
            }
            self.closureArr.removeAll()
            self.mainQueue.async {
                closure()
            }
        }
    }

    // MARK: - 并发
    /// 并发添加任务
    ///
    /// - Parameter closure: 任务闭包
    /// - Returns: GCDKit
    func concurrentTask(closure: @escaping GCDKitClosure) -> Self {
        let queue = DispatchQueue(label: "", attributes: .concurrent)
        let workItem = DispatchWorkItem(block: closure)

        queue.async(group: group, execute: workItem)
        return self
    }

    /// 并发添加任务，并且会排斥其他任务执行,保证线程安全的
    ///
    /// - Parameter closure: 任务闭包
    /// - Returns: GCDKit
    func barrierClosure(closure: @escaping GCDKitClosure) -> Self {
        let queue = DispatchQueue(label: "", attributes: .concurrent)
        let workItem = DispatchWorkItem(flags: .barrier, block: closure)
        queue.async(group: group, execute: workItem)
        return self
    }

    /// 所有并发完成后执行
    ///
    /// - Parameter closure: 完成闭包
    func allTaskDone(closure: @escaping GCDKitClosure) {
        group.notify(queue: .main, execute: closure)
    }

    // MARK: - 延迟
    /// 延迟执行方法
    ///
    /// - Parameters:
    ///   - time: 延迟时间：.now() + Double
    ///   - task: 闭包
    /// - Returns: 延迟执行任务对象
    @discardableResult
    func delay(_ time: DispatchTime, task: @escaping () -> Void) -> DelayTask? {

        func dispatch_Later(block: @escaping () -> Void) {
            DispatchQueue.main.asyncAfter(deadline:time, execute: block)
        }

        var closure: (() -> Void)? = task
        var result: DelayTask?

        let delayedClosure: DelayTask = {
            cancel in
            if let internalClosure = closure {
                if (cancel == false) {
                    DispatchQueue.main.async(execute: internalClosure)
                }
            }
            closure = nil
            result = nil
        }

        result = delayedClosure

        dispatch_Later {
            if let delayedClosure = result {
                delayedClosure(false)
            }
        }
        return result
    }

    /// 取消延迟执行的方法
    ///
    /// - Parameter task: 延迟执行对象
    func cancel(_ task:DelayTask?) {
        task?(true)
    }

    // MARK: - 定时器
    /// 定时器
    ///
    /// - Parameters:
    ///   - start: 开始时间，默认现在开始
    ///   - end: 结束时间
    ///   - repeating: 重复时间
    ///   - leeway: 偏差时间，默认 1 微秒
    ///   - closure: 执行闭包
    ///   - cancelClosure: 完成闭包
    func timer(start: DispatchTime = .now(), end: DispatchTime, repeating: Double, leeway: DispatchTimeInterval = .microseconds(1), closure:@escaping GCDKitClosure,cancelClosure: @escaping GCDKitClosure) {
        let timer = DispatchSource.makeTimerSource()
        timer.setEventHandler(handler: closure)
        timer.setCancelHandler(handler: cancelClosure)
        timer.schedule(deadline: start, repeating: repeating, leeway: leeway)
        timer.resume()

        delay(end) {
            timer.cancel()
        }

    }

}
